#include "PartOfBattle.h"
#include <iostream>
#include <ctime>

#define USE_STATIC_DATA 1

PartOfBattle::PartOfBattle(bool _transformX, bool _transformY)
	:m_transformX(_transformX)
	,m_transformY(_transformY)
	,m_existShip(false)
	,m_lock(false)
{
	for (int i=0;i<MAX_H/2;i++)
		for (int j=0;j<MAX_V/2;j++)
		{
			m_table[i][j] = -1; // -1: unkown, 0:no ship, 1:ship
			m_count[i][j] = 0;
		}
}

PartOfBattle::~PartOfBattle()
{
}
//check battle contain a point or not
bool PartOfBattle::IsContain(Point p)
{
	int posX = p.first;
	int posY = p.second;
	if (m_transformX) posX = MAX_H - posX - 1;
	if (m_transformY) posY = MAX_V - posY - 1;
	if (posX < 0 || posX >= MAX_H/2) return false;
	if (posY < 0 || posY >= MAX_V/2) return false;
	return true;
}
//end

//new point is recognized, add it to table
void PartOfBattle::SetValue(Point p, bool value)
{
	if (!IsContain(p)) return; // exit, don't have this point

	time_t startt, endt;
	time(&startt);

	int posX = p.first;
	int posY = p.second;
	if (m_transformX) posX = MAX_H - posX - 1;
	if (m_transformY) posY = MAX_V - posY - 1;
	//std::cout << posX << ":" << posY << std::endl;
	//assign value
	if (m_table[posX][posY] != -1)
	{
		std::cout << "Problem!!!!!!!"<< std::endl;
	}

	m_table[posX][posY] = (value)?1:0;
	//std::cout << m_table[posX][posY] << std::endl;
	// check to remove
	ListOfEncode::iterator ii;
	ListOfEncode toRemove;
	ListOfEncode newPosibility;
	for (ii = m_posibility.begin(); ii != m_posibility.end(); ii++)
	{
		if (value != GetValue(*ii,posX,posY))
		{
			toRemove.push_back(*ii);
			//RemovePosibility(*ii);
		}
		else
		{
			newPosibility.push_back(*ii);
		}
	}
	if (toRemove.size() > newPosibility.size())
	{
		std::cout << "Choose 1"<< std::endl;
		RefreshCount(newPosibility);
	}
	else
	{
		std::cout << "Chose 2" << std::endl;
		Lock();
		RemovePosibility(toRemove);
		m_posibility = newPosibility;
		Unlock();
	}
	//exist ship?
	if (value)
	{
		m_existShip = true;
	}
	time(&endt);
	std::cout << "SetValue: " << difftime(endt,startt) << std::endl;

}
//end

// get value from an encode
bool PartOfBattle::GetValue(unsigned int encode, int posX, int posY)
{
	int power = posX * (MAX_H/2) + posY;
	return ((1 << power) & encode) == (1 << power);
}

bool PartOfBattle::GetValue(unsigned int encode, Ship::TypeOfShip type)
{
	int power = 25 + type;
	return ((1 << power) & encode) == (1 << power);
}
//endl

// remove an encode
void PartOfBattle::RemovePosibility(ListOfEncode listOfEncode)
{
	ListOfEncode::iterator ii;
	for (ii = listOfEncode.begin(); ii != listOfEncode.end(); ii++)
	{
		for (int i=0; i<MAX_H/2;i++)
			for (int j=0; j<MAX_V/2;j++)
				if (GetValue(*ii,i,j))
				{
					m_count[i][j]--;
				}
	}
}
//end

// add a posibility
void PartOfBattle::InsertPosibility(unsigned int _encode)
{
#if ENABLE_SCAN 
	std::pair<SetOfEncode::iterator,bool> result = m_posibility.insert(_encode);
#else
	m_posibility.push_back(_encode);
#endif
#if !USE_STATIC_DATA
	if (result.second)
	{
		for (int i=0; i<MAX_H/2;i++)
			for (int j=0; j<MAX_V/2;j++)
				if (GetValue(_encode,i,j))
				{
					m_count[i][j]++;
				}
	}
	else
	{
		std::cout << "Problem 3. Bong Fix it!!!" << std::endl;
	}
#endif
}
//end

// add many
void PartOfBattle::InsertPosibility(ListOfEncode _setOfEncode)
{
#if !USE_STATIC_DATA
	SetOfEncode::iterator ii;
	for (ii = _setOfEncode.begin(); ii != _setOfEncode.end(); ii++)
	{
		InsertPosibility(*ii);
	}
#else
	//m_posibility = _setOfEncode; // use static data, optimize
	RefreshCount(_setOfEncode);
#endif
}
//end

//get number of posibiliti per cell
int PartOfBattle::GetCount(Point p)
{
	if (!IsContain(p)) return 0; // exit, don't have this point

	int posX = p.first;
	int posY = p.second;
	if (m_transformX) posX = MAX_H - posX - 1;
	if (m_transformY) posY = MAX_V - posY - 1;
	//std::cout << posX << ":" << posY << std::endl;
	Lock();
	int result = m_count[posX][posY];
	Unlock();
	return result;
}//end

//get weight per cell
// depend on is there any ship in this cell or not
int PartOfBattle::GetWeight()
{
	return (m_existShip)?m_posibility.size():(m_posibility.size() + 500000);
}
//end

//check is a position unknown or not
bool PartOfBattle::IsUnkown(Point p)
{
	if (!IsContain(p)) return 0; // exit, don't have this point

	int posX = p.first;
	int posY = p.second;
	if (m_transformX) posX = MAX_H - posX - 1;
	if (m_transformY) posY = MAX_V - posY - 1;

	return m_table[posX][posY] == -1;
}//end

void PartOfBattle::SetCount(int _count[5][5])
{
	for (int i=0;i<MAX_H/2;i++)
		for (int j=0;j<MAX_V/2;j++)
		{
			m_count[i][j] = _count[i][j];
		}
}//end

//refresh count table
void PartOfBattle::RefreshCount(ListOfEncode newPosibility)
{
	Lock();
	int newCount [5][5];
	for (int i=0; i <MAX_H/2;i++)
		for (int j=0;j<MAX_V/2;j++)
		{
			newCount[i][j] = 0;
		}

	ListOfEncode::iterator ii;
	for (ii = newPosibility.begin(); ii != newPosibility.end(); ii++)
	{
		unsigned int encode = *ii;
		for (int i=0; i<MAX_H/2;i++)
			for (int j=0; j<MAX_V/2;j++)
				if (GetValue(encode,i,j))
				{
					newCount[i][j]++;
				}
	}
	//m_count = newCount;
	m_posibility = newPosibility;
	SetCount(newCount);
	Unlock();
}
//end

//check is contain ship or not
bool PartOfBattle::IsContainShip(ShipPtr ship)
{
	PointSet posSet = ship->GetPos();
	PointSet::iterator ii;
	for (ii=posSet.begin(); ii != posSet.end(); ii++)
	{
		if (this->IsContain(*ii))
		{
			return true;
		}
	}
	return false;
}
//end

//remove all ship with a type
void PartOfBattle::RemoveShipType(Ship::TypeOfShip type)
{
	time_t startt, endt;
	time(&startt);
	//std::cout << "before: " << m_posibility.size() << std::endl;
	// check to remove
	ListOfEncode::iterator ii;
	ListOfEncode newPosibility;
    ListOfEncode toRemove;
	for (ii = m_posibility.begin(); ii != m_posibility.end(); ii++)
	{
		if (GetValue(*ii,type))
		{
			//toRemove.push_back(*ii);
			//RemovePosibility(*ii);
		}
		else
		{
			newPosibility.push_back(*ii);
		}
	}
 //   Lock();
	//RemovePosibility(toRemove);
	//m_posibility = newPosibility;
 //   Unlock();
    RefreshCount(newPosibility);
	time(&endt);
	std::cout << "Remove ship type: " << difftime(endt,startt) << std::endl;
	std::cout << "left: " << m_posibility.size() << std::endl;
}
//end

//lock & unlock resource
void PartOfBattle::Lock()
{
	while (m_lock)
	{
		std::cout << "Locked" << std::endl;
	}
	m_lock = true;
}

void PartOfBattle::Unlock()
{
	m_lock = false;
}